﻿namespace System.Data.Mapping
{
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Data.Metadata.Edm;
    using System.Data.Objects;
    using System.Diagnostics;
    using System.Globalization;
    using System.Linq;
    using System.Reflection;
    using System.Runtime.CompilerServices;
    using System.Threading;

    internal static class MetadataWorkspaceUtilities
    {
        public static MetadataWorkspace CreateMetadataWorkspace(Type contextType)
        {
            MetadataWorkspace workspace = null;
            workspace = CreateMetadataWorkspaceFromResources(contextType, typeof(ObjectContext));
            if (workspace == null)
            {
                throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, System.Data.Mapping.MetadataResource.LinqToEntitiesProvider_UnableToRetrieveMetadata, new object[] { contextType.Name }));
            }
            return workspace;
        }

        public static MetadataWorkspace CreateMetadataWorkspaceFromResources(Type contextType, Type baseContextType)
        {
            foreach (MetadataWorkspaceInfo info in GetMetadataWorkspaceInfos(FindMetadataResources(contextType.Assembly)))
            {
                EdmItemCollection edmCollection = new EdmItemCollection(new string[] { info.Csdl });
                for (Type type = contextType; (type != baseContextType) && (type != typeof(object)); type = type.BaseType)
                {
                    EntityContainer container;
                    if (edmCollection.TryGetEntityContainer(type.Name, out container))
                    {
                        StoreItemCollection storeCollection = new StoreItemCollection(new string[] { info.Ssdl });
                        StorageMappingItemCollection collection = new StorageMappingItemCollection(edmCollection, storeCollection, new string[] { info.Msl });
                        MetadataWorkspace workspace = new MetadataWorkspace();
                        workspace.RegisterItemCollection(edmCollection);
                        workspace.RegisterItemCollection(storeCollection);
                        workspace.RegisterItemCollection(collection);
                        workspace.RegisterItemCollection(new ObjectItemCollection());
                        return workspace;
                    }
                }
            }
            return null;
        }

        private static IEnumerable<string> FindMetadataResources(Assembly assembly)
        {
            foreach (string iteratorVariable0 in assembly.GetManifestResourceNames())
            {
                if (MetadataWorkspaceInfo.IsMetadata(iteratorVariable0))
                {
                    yield return string.Format("res://{0}/{1}", assembly.FullName, iteratorVariable0);
                }
            }
        }

        private static IEnumerable<MetadataWorkspaceInfo> GetMetadataWorkspaceInfos(IEnumerable<string> resourcePaths)
        {
            foreach (IGrouping<string, string> iteratorVariable0 in resourcePaths.GroupBy<string, string>(p => p.Substring(0, p.LastIndexOf('.')), StringComparer.InvariantCultureIgnoreCase))
            {
                yield return MetadataWorkspaceInfo.Create(iteratorVariable0);
            }
        }



        private class MetadataWorkspaceInfo
        {
            private const string CSDL_EXT = ".csdl";
            private const string MSL_EXT = ".msl";
            private const string SSDL_EXT = ".ssdl";

            public MetadataWorkspaceInfo(string csdlPath, string mslPath, string ssdlPath)
            {
                if (csdlPath == null)
                {
                    throw new ArgumentNullException("csdlPath");
                }
                if (mslPath == null)
                {
                    throw new ArgumentNullException("mslPath");
                }
                if (ssdlPath == null)
                {
                    throw new ArgumentNullException("ssdlPath");
                }
                this.Csdl = csdlPath;
                this.Msl = mslPath;
                this.Ssdl = ssdlPath;
            }

            public static System.Data.Mapping.MetadataWorkspaceUtilities.MetadataWorkspaceInfo Create(IEnumerable<string> paths)
            {
                string csdlPath = null;
                string mslPath = null;
                string ssdlPath = null;
                foreach (string str4 in paths)
                {
                    if (str4.EndsWith(".csdl", StringComparison.OrdinalIgnoreCase))
                    {
                        csdlPath = str4;
                    }
                    else if (str4.EndsWith(".msl", StringComparison.OrdinalIgnoreCase))
                    {
                        mslPath = str4;
                    }
                    else if (str4.EndsWith(".ssdl", StringComparison.OrdinalIgnoreCase))
                    {
                        ssdlPath = str4;
                    }
                }
                return new System.Data.Mapping.MetadataWorkspaceUtilities.MetadataWorkspaceInfo(csdlPath, mslPath, ssdlPath);
            }

            public static bool IsMetadata(string path)
            {
                if (!path.EndsWith(".csdl", StringComparison.OrdinalIgnoreCase) && !path.EndsWith(".msl", StringComparison.OrdinalIgnoreCase))
                {
                    return path.EndsWith(".ssdl", StringComparison.OrdinalIgnoreCase);
                }
                return true;
            }

            public string Csdl { get; private set; }

            public string Msl { get; private set; }

            public string Ssdl { get; private set; }
        }
    }
}

